<template>
	<view class="lime-echart" :style="customStyle" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
		<!-- #ifndef APP-NVUE -->
		<canvas class="lime-echart__canvas" v-if="use2dCanvas" type="2d" :id="canvasId" :style="canvasStyle"
			:disable-scroll="isDisableScroll" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" />
		<canvas class="lime-echart__canvas" v-else :width="nodeWidth" :height="nodeHeight" :style="canvasStyle"
			:canvas-id="canvasId" :id="canvasId" :disable-scroll="isDisableScroll" @touchstart="touchStart"
			@touchmove="touchMove" @touchend="touchEnd" />
		<view class="lime-echart__mask" v-if="isPC" @mousedown="touchStart" @mousemove="touchMove" @mouseup="touchEnd"
			@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
		</view>
		<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
		<!-- #endif -->
		<!-- #ifdef APP-NVUE -->
		<web-view class="lime-echart__canvas" :id="canvasId" :style="canvasStyle" :webview-styles="webviewStyles"
			ref="webview" src="/uni_modules/lime-echart/static/nvue.html?v=1" @pagefinish="finished = true"
			@onPostMessage="onMessage"></web-view>
		<!-- #endif -->
	</view>
</template>

<script>
	// #ifdef VUE3
	// #ifdef APP-PLUS
	global = {}
	// #endif
	// #endif
	// #ifndef APP-NVUE
	import {
		Canvas,
		setCanvasCreator,
		dispatch
	} from './canvas';
	import {
		wrapTouch,
		convertTouchesToArray,
		devicePixelRatio,
		sleep,
		canIUseCanvas2d,
		getRect
	} from './utils';
	// #endif
	// #ifdef APP-NVUE
	import {
		base64ToPath,
		sleep
	} from './utils';
	import {
		Echarts
	} from './nvue'
	// #endif
	const charts = {}
	const echartsObj = {}
	export default {
		name: 'lime-echart',
		props: {
			widths: {
				type: Number,
			},
			heights: {
				type: Number,
			},
			// #ifdef MP-WEIXIN || MP-TOUTIAO
			type: {
				type: String,
				default: '2d'
			},
			// #endif
			// #ifdef APP-NVUE
			webviewStyles: Object,
			// hybrid: Boolean,
			// #endif
			customStyle: String,
			isDisableScroll: Boolean,
			isClickable: {
				type: Boolean,
				default: true
			},
			enableHover: Boolean,
			beforeDelay: {
				type: Number,
				default: 30
			},

		},
		data() {
			return {
				// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
				use2dCanvas: true,
				// #endif
				// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
				use2dCanvas: false,
				// #endif
				ariaLabel: '图表',
				width: null,
				height: null,
				nodeWidth: null,
				nodeHeight: null,
				// canvasNode: null,
				config: {},
				inited: false,
				finished: false,
				file: '',
				platform: '',
				isPC: false,
				isDown: false,
				isOffscreenCanvas: false,
				offscreenWidth: 0,
				offscreenHeight: 0
			};
		},
		computed: {
			canvasId() {
				return `lime-echart${this._ && this._.uid || this._uid}`
			},
			offscreenCanvasId() {
				return `${this.canvasId}_offscreen`
			},
			offscreenStyle() {
				console.log(this.offscreenWidth, '--------------------------offwidth')
				console.log(this.offscreenHeight, '--------------------------offwidth')
				return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
			},
			canvasStyle() {
				console.log(this.width, 'width---------------')
				console.log(this.height, 'height--------------')
				return this.width && this.height ? ('width:' + this.widths + 'rpx;height:' + this.heights + 'rpx') : ''
			}
		},
		// #ifndef VUE3
		beforeDestroy() {
			this.clear()
			this.dispose()
			// #ifdef H5
			if (this.isPC) {
				document.removeEventListener('mousewheel', this.mousewheel)
			}
			// #endif
		},
		// #endif
		// #ifdef VUE3
		beforeUnmount() {
			this.clear()
			this.dispose()
			// #ifdef H5
			if (this.isPC) {
				document.removeEventListener('mousewheel', this.mousewheel)
			}
			// #endif
		},
		// #endif
		created() {
			// #ifdef H5
			if (!('ontouchstart' in window)) {
				this.isPC = true
				document.addEventListener('mousewheel', this.mousewheel)
			}
			// #endif
			// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
			const {
				platform
			} = uni.getSystemInfoSync();
			this.isPC = /windows/i.test(platform)
			// #endif
			this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
		},
		mounted() {
			this.$nextTick(() => {
				this.$emit('finished')
			})
		},
		methods: {
			// #ifdef APP-NVUE
			onMessage(e) {
				const res = e?.detail?.data[0] || null;
				if (res?.event) {
					const data = JSON.parse(res.data)
					if (res.event === 'inited') {
						this.inited = true
					} else if (res.event.startsWith('@')) {
						this.chart.dispatchAction(res.event.split('@')[1], data.options)
					}

					this.$emit(res.event, data);
				} else if (res?.file) {
					this.file = res.data
				} else if (!res[0] && JSON.stringify(res[0]) != '{}') {
					console.error(res);
				} else {
					console.log(...res)
				}
			},
			// #endif
			setChart(callback) {
				if (!this.chart) {
					console.warn(`组件还未初始化，请先使用 init`)
					return
				}
				if (typeof callback === 'function' && this.chart) {
					callback(this.chart);
				}
				// #ifdef APP-NVUE
				if (typeof callback === 'function') {
					this.$refs.webview.evalJs(
						`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
				}
				// #endif
			},
			setOption() {
				if (!this.chart || !this.chart.setOption) {
					console.warn(`组件还未初始化，请先使用 init`)
					return
				}
				this.chart.setOption(...arguments);
			},
			showLoading() {
				if (this.chart) {
					this.chart.showLoading(...arguments)
				}
			},
			hideLoading() {
				if (this.chart) {
					this.chart.hideLoading()
				}
			},
			clear() {
				if (this.chart) {
					this.chart.clear()
				}
			},
			dispose() {
				if (this.chart) {
					this.chart.dispose()
				}
			},
			resize(size) {
				if (size && size.width && size.height) {
					this.height = size.height
					this.width = size.width
					if (this.chart) {
						this.chart.resize(size)
					}
				} else {
					this.$nextTick(() => {
						uni.createSelectorQuery()
							.in(this)
							.select(`.lime-echart`)
							.boundingClientRect()
							.exec(res => {
								if (res) {
									let {
										width,
										height
									} = res[0];
									this.width = width = width || 300;
									this.height = height = height || 300;
									this.chart.resize({
										width,
										height
									})
								}
							});
					})

				}

			},
			canvasToTempFilePath(args = {}) {
				// #ifndef APP-NVUE
				const {
					use2dCanvas,
					canvasId
				} = this;
				return new Promise((resolve, reject) => {
					const copyArgs = Object.assign({
						canvasId,
						success: resolve,
						fail: reject
					}, args);
					if (use2dCanvas) {
						delete copyArgs.canvasId;
						copyArgs.canvas = this.canvasNode;
					}
					uni.canvasToTempFilePath(copyArgs, this);
				});
				// #endif
				// #ifdef APP-NVUE
				this.file = ''
				this.$refs.webview.evalJs(`canvasToTempFilePath()`);
				return new Promise((resolve, reject) => {
					this.$watch('file', async (file) => {
						if (file) {
							const tempFilePath = await base64ToPath(file)
							resolve(args.success({
								tempFilePath
							}))
						} else {
							reject(args.fail({
								error: ``
							}))
						}
					})
				})
				// #endif
			},
			async init(echarts, ...args) {
				// #ifndef APP-NVUE
				if (args && args.length == 0 && !echarts) {
					console.error('缺少参数：init(echarts, theme?:string, opts?: object, callback?: function)')
					return
				}
				// #endif
				let theme = null,
					opts = {},
					callback;

				Array.from(arguments).forEach(item => {
					if (typeof item === 'function') {
						callback = item
					}
					if (['string'].includes(typeof item)) {
						theme = item
					}
					if (typeof item === 'object') {
						opts = item
					}
				})

				if (this.beforeDelay) {
					await sleep(this.beforeDelay)
				}
				let config = await this.getContext();
				// #ifndef APP-NVUE
				setCanvasCreator(echarts, config)
				this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
				if (typeof callback === 'function') {
					callback(this.chart)
				} else {
					return this.chart
				}
				// #endif
				// #ifdef APP-NVUE
				this.chart = new Echarts(this.$refs.webview)
				this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
				if (callback) {
					callback(this.chart)
				} else {
					return this.chart
				}
				// #endif
			},
			getContext() {
				// #ifdef APP-NVUE
				if (this.finished) {
					return Promise.resolve(this.finished)
				}
				return new Promise(resolve => {
					this.$watch('finished', (val) => {
						if (val) {
							resolve(this.finished)
						}
					})
				})
				// #endif
				// #ifndef APP-NVUE
				return getRect(`#${this.canvasId}`, {
					context: this,
					type: this.use2dCanvas ? 'fields' : 'boundingClientRect'
				}).then(res => {
					if (res) {
						let dpr = devicePixelRatio
						let {
							width,
							height,
							node
						} = res
						let canvas;
						this.width = width = width || 300;
						this.height = height = height || 300;
						if (node) {
							const ctx = node.getContext('2d');
							canvas = new Canvas(ctx, this, true, node);
							this.canvasNode = node
						} else {
							// #ifdef MP-TOUTIAO
							dpr = !this.isPC ? devicePixelRatio : 1 // 1.25
							// #endif
							// #ifndef MP-ALIPAY || MP-TOUTIAO
							dpr = this.isPC ? devicePixelRatio : 1
							// #endif
							// #ifdef MP-ALIPAY || MP-LARK
							dpr = devicePixelRatio
							// #endif
							this.rect = res
							this.nodeWidth = width * dpr;
							this.nodeHeight = height * dpr;
							const ctx = uni.createCanvasContext(this.canvasId, this);
							canvas = new Canvas(ctx, this, false);
						}
						return {
							canvas,
							width,
							height,
							devicePixelRatio: dpr,
							node
						};
					} else {
						return {}
					}
				})
				// #endif
			},
			// #ifndef APP-NVUE
			getRelative(e, touches) {
				let {
					clientX,
					clientY
				} = e
				if (!(clientX && clientY) && touches && touches[0]) {
					clientX = touches[0].clientX
					clientY = touches[0].clientY
				}
				return {
					x: clientX - this.rect.left,
					y: clientY - this.rect.top,
					wheelDelta: e.wheelDelta || 0
				}
			},
			getTouch(e, touches) {
				const {
					x
				} = touches && touches[0] || {}
				return x ? touches[0] : this.getRelative(e, touches);
			},
			touchStart(e) {
				this.isDown = true
				const next = () => {
					const touches = convertTouchesToArray(e.touches)
					if (this.chart) {
						const touch = this.getTouch(e, touches)
						this.startX = touch.x
						this.startY = touch.y
						this.startT = new Date()
						const handler = this.chart.getZr().handler;
						dispatch.call(handler, 'mousedown', touch)
						dispatch.call(handler, 'mousemove', touch)
						handler.processGesture(wrapTouch(e), 'start');
						clearTimeout(this.endTimer);
					}

				}
				if (this.isPC) {
					getRect(`#${this.canvasId}`, {
						context: this
					}).then(res => {
						this.rect = res
						next()
					})
					return
				}
				next()
			},
			touchMove(e) {
				if (this.isPC && this.enableHover && !this.isDown) {
					this.isDown = true
				}
				const touches = convertTouchesToArray(e.touches)
				if (this.chart && this.isDown) {
					const handler = this.chart.getZr().handler;
					dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
					handler.processGesture(wrapTouch(e), 'change');
				}

			},
			touchEnd(e) {
				this.isDown = false
				if (this.chart) {
					const touches = convertTouchesToArray(e.changedTouches)
					const {
						x
					} = touches && touches[0] || {}
					const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
					const handler = this.chart.getZr().handler;
					const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
					dispatch.call(handler, 'mouseup', touch)
					handler.processGesture(wrapTouch(e), 'end');
					if (isClick) {
						dispatch.call(handler, 'click', touch)
					} else {
						this.endTimer = setTimeout(() => {
							dispatch.call(handler, 'mousemove', {
								x: 999999999,
								y: 999999999
							});
							dispatch.call(handler, 'mouseup', {
								x: 999999999,
								y: 999999999
							});
						}, 50)
					}
				}
			},
			// #endif
			// #ifdef H5
			mousewheel(e) {
				if (this.chart) {
					dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
				}
			}
			// #endif
		}
	};
</script>
<style>
	.lime-echart {
		position: relative;
		/* #ifndef APP-NVUE */
		width: 100%;
		height: 100%;
		/* #endif */
		/* #ifdef APP-NVUE */
		flex: 1;
		/* #endif */
	}

	.lime-echart__canvas {
		/* #ifndef APP-NVUE */
		width: 100%;
		height: 100%;
		/* #endif */
		/* #ifdef APP-NVUE */
		flex: 1;
		/* #endif */
	}

	/* #ifndef APP-NVUE */
	.lime-echart__mask {
		position: absolute;
		width: 100%;
		height: 100%;
		left: 0;
		top: 0;
		z-index: 1;
	}

	/* #endif */
</style>